
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <string.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h> 
#include <sys/mman.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>

#include "fpga_io.h"
//#include "axi_dev.h"
#define _DBG_LEVEL		_DBG_INFO
//#include "printf.h"

/****************************************************************************************
* fpga I/O 控制寄存器操作
*****************************************************************************************/
typedef struct fpga_handler_t
{
	char*				name;
	uint32_t*  			phys_address;  	///< 寄存器物理地址
	volatile uint32_t*  base_address;  	///< 寄存器虚拟基地址
	int                 size;           ///< 地址长度(bytes)
	int 				fd;
	TFpgaVersion		version;
} fpga_handler_t;

fpga_handler_t fpga_handler =
{
	.name = "fpga_handler",
	.phys_address = (void*)0x41200000,  ///< 基地址
	.size = 1024 * 4,       		///< 长度
};

#define FPGA_DEBUG 1
#if FPGA_DEBUG
#define PCL_NONE				 "\e[0m"
#define PCL_YELLOW				 "\e[1;33m"
#define PCL_RED 				 "\e[0;31m"

#define dbg_printf(...)   \
	do{ printf(PCL_NONE "[%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

	
#define dbg_info(...)   \
		do{ printf(PCL_NONE "[%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)
	
#define dbg_warn(...)   \
		do{ printf(PCL_YELLOW "[warn,%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

#define dbg_error(...)   \
	do{ printf(PCL_RED "[error,%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

#define dbg_fatal(...)   \
	do{ printf(PCL_RED "[fatal,%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

#else
#define dbg_error(...)
#define dbg_fatal(...)
#define dbg_warn(...)
#define dbg_printf(...)
#endif


#define barrier()  __asm__ __volatile__("": : :"memory")

// 读寄存器
unsigned int fpga_register_get(int offset)
{
	fpga_handler_t *this = &fpga_handler;
	return this->base_address[offset];
	barrier();
}
// 写寄存器
void fpga_register_set(int offset, unsigned int val)
{
	fpga_handler_t *this = &fpga_handler;
	if(this->fd == 0)
		return;
	
	this->base_address[offset] = val;
	barrier();
}
// 与寄存器
void fpga_register_and(int offset, unsigned int val)
{
	fpga_handler_t *this = &fpga_handler;
	if(this->fd == 0)
		return;
	
	this->base_address[offset] &= val;
	barrier();
}

// 或寄存器
void fpga_register_or(int offset, unsigned int val)
{
	fpga_handler_t *this = &fpga_handler;
	if(this->fd == 0)
		return;
	
	this->base_address[offset] |= val;
	barrier();
}

// 异或寄存器
void fpga_register_xor(int offset, unsigned int val)
{
	fpga_handler_t *this = &fpga_handler;
	if(this->fd == 0)
		return;
	
	this->base_address[offset] ^= val;
	barrier();
}

// 打开
int fpga_register_open(void)
{
	fpga_handler_t *this = &fpga_handler;
	
	if (this->fd > 0) 
		return -1;
	
	this->fd = open("/dev/mem", O_RDWR | O_SYNC);
	if (this->fd < 0)
	{
		dbg_error("open(/dev/mem) error\n");
		return -1;
	}
	this->base_address = mmap(NULL, this->size, PROT_READ | PROT_WRITE, MAP_SHARED,
	                          this->fd, (off_t)this->phys_address);
	if (this->base_address == MAP_FAILED)
	{
		this->base_address = NULL;
		dbg_error("%s.mmap(phys_address) error\n", this->name);
		return -1;
	}

	return 0;
}

// 关闭
int fpga_register_close(void)
{
	fpga_handler_t *this = &fpga_handler;
	
	if (this->fd == 0) 
		return 0;
	
	munmap((void *)this->base_address, this->size);
	close(this->fd);
	this->fd = 0;
	
	return 0;
}


const TFpgaVersion *fpga_get_version(void)
{
	return &fpga_handler.version;
}

EHardVer get_hardware_ver(void)
{
	uint32_t ver = fpga_handler.version.time & 0xFF;

	if ( ver == 0x31 ) {
		return HARDWARE_VER_S_V2;
	}
	else if ( ver == 0x30 ) {
		return HARDWARE_VER_S_V1;
	}

	return HARDWARE_VER_S_V_NONE;
}


